﻿namespace h3
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;

    public class MultiThreadFileCopier
    {
        private string sourceDir;
        private string targetDir;
        private int maxThreads;
        private int copiedFiles;
        private int totalFiles;
        private object lockObject = new object();

        public MultiThreadFileCopier(string source, string target, int maxThreads = 4)
        {
            sourceDir = source;
            targetDir = target;
            this.maxThreads = maxThreads;

            // 确保目标目录存在
            if (!Directory.Exists(targetDir))
            {
                Directory.CreateDirectory(targetDir);
            }
        }

        public async Task CopyFilesAsync()
        {
            // 获取所有文件
            string[] files = Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories);
            totalFiles = files.Length;
            copiedFiles = 0;

            Console.WriteLine($"发现 {totalFiles} 个文件需要拷贝");
            Console.WriteLine($"使用 {maxThreads} 个线程进行拷贝...");

            // 使用SemaphoreSlim控制并发线程数
            var semaphore = new SemaphoreSlim(maxThreads);
            var tasks = new List<Task>();

            foreach (string file in files)
            {
                await semaphore.WaitAsync();

                tasks.Add(Task.Run(() =>
                {
                    try
                    {
                        CopySingleFile(file);
                    }
                    finally
                    {
                        semaphore.Release();
                    }
                }));
            }

            // 等待所有任务完成
            await Task.WhenAll(tasks);

            Console.WriteLine($"\n拷贝完成！成功拷贝 {copiedFiles}/{totalFiles} 个文件");
        }

        private void CopySingleFile(string sourceFile)
        {
            try
            {
                // 构建目标文件路径
                string relativePath = Path.GetRelativePath(sourceDir, sourceFile);
                string targetFile = Path.Combine(targetDir, relativePath);

                // 确保目标目录存在
                string targetDirPath = Path.GetDirectoryName(targetFile);
                if (!Directory.Exists(targetDirPath))
                {
                    Directory.CreateDirectory(targetDirPath);
                }

                // 使用FileStream进行大文件拷贝
                using (FileStream sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read))
                using (FileStream targetStream = new FileStream(targetFile, FileMode.Create, FileAccess.Write))
                {
                    byte[] buffer = new byte[81920]; // 80KB缓冲区
                    int bytesRead;

                    while ((bytesRead = sourceStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        targetStream.Write(buffer, 0, bytesRead);
                    }
                }

                // 更新进度
                lock (lockObject)
                {
                    copiedFiles++;
                    Console.WriteLine($"({copiedFiles}/{totalFiles}) 已拷贝: {Path.GetFileName(sourceFile)}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"拷贝文件 {sourceFile} 失败: {ex.Message}");
            }
        }
    }

    // 测试类
    class Program
    {
        static async Task Main(string[] args)
        {
            string sourceDirectory = @"D:\visual\my_visual\C#\csharp-ch5-homework\h3\TestSource";
            string targetDirectory = @"D:\visual\my_visual\C#\csharp-ch5-homework\h3\TestTarget";

            // 创建测试目录和文件（实际使用时注释掉）
            // CreateTestFiles(sourceDirectory);

            var copier = new MultiThreadFileCopier(sourceDirectory, targetDirectory, 4);

            Console.WriteLine("开始文件拷贝...");
            var startTime = DateTime.Now;

            await copier.CopyFilesAsync();

            var endTime = DateTime.Now;
            Console.WriteLine($"总耗时: {(endTime - startTime).TotalSeconds:F2}秒");
        }

        // 创建测试文件的辅助方法
        static void CreateTestFiles(string directory)
        {
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            // 创建一些测试文件
            for (int i = 0; i < 10; i++)
            {
                string filePath = Path.Combine(directory, $"testfile_{i}.dat");
                using (FileStream fs = new FileStream(filePath, FileMode.Create))
                {
                    // 创建约50MB的文件
                    byte[] data = new byte[1024 * 1024]; // 1MB
                    new Random().NextBytes(data);

                    for (int j = 0; j < 50; j++)
                    {
                        fs.Write(data, 0, data.Length);
                    }
                }
            }
        }
    }
}
